
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>执行查询 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../../_static/jquery.js"></script>
    <script type="text/javascript" src="../../_static/underscore.js"></script>
    <script type="text/javascript" src="../../_static/doctools.js"></script>
    <script type="text/javascript" src="../../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../../genindex.html" />
    <link rel="search" title="搜索" href="../../search.html" />
    <link rel="next" title="聚合" href="aggregation.html" />
    <link rel="prev" title="模型" href="models.html" />



 
<script src="../../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../../index.html">Home</a>  |
        <a title="Table of contents" href="../../contents.html">Table of contents</a>  |
        <a title="Global index" href="../../genindex.html">Index</a>  |
        <a title="Module index" href="../../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="models.html" title="模型">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="aggregation.html" title="聚合">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="topics-db-queries">
            
  <div class="section" id="s-making-queries">
<span id="making-queries"></span><h1>执行查询<a class="headerlink" href="#making-queries" title="永久链接至标题">¶</a></h1>
<p>一旦创建 <a class="reference internal" href="models.html"><span class="doc">数据模型</span></a> 后，Django 自动给予你一套数据库抽象 API，允许你创建，检索，更新和删除对象。本页介绍如何使用这些 API。参考 <a class="reference internal" href="../../ref/models/index.html"><span class="doc">数据模型参考</span></a> 获取所有查询选项的完整细节。</p>
<p>在本指南中（以及相关参考资料中），我们将引用以下模型，这些模型包含了一个 Webblog 应用：</p>
<div class="highlight-python notranslate" id="queryset-model-example"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">Blog</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">tagline</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>

<span class="k">class</span> <span class="nc">Author</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
    <span class="n">email</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">EmailField</span><span class="p">()</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>

<span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">blog</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Blog</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">)</span>
    <span class="n">headline</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">255</span><span class="p">)</span>
    <span class="n">body_text</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>
    <span class="n">pub_date</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>
    <span class="n">mod_date</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>
    <span class="n">authors</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span><span class="n">Author</span><span class="p">)</span>
    <span class="n">number_of_comments</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span>
    <span class="n">number_of_pingbacks</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span>
    <span class="n">rating</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">headline</span>
</pre></div>
</div>
<div class="section" id="s-creating-objects">
<span id="creating-objects"></span><h2>创建对象<a class="headerlink" href="#creating-objects" title="永久链接至标题">¶</a></h2>
<p>为了用 Python 对象展示数据表对象，Django 使用了一套直观的系统：一个模型类代表一张数据表，一个模型类的实例代表数据库表中的一行记录。</p>
<p>要创建一个对象，用关键字参数初始化它，然后调用 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 将其存入数据库。</p>
<p>假设模型都位于文件 <code class="docutils literal notranslate"><span class="pre">mysite/blog/models.py</span></code> 中，这是一个例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">blog.models</span> <span class="kn">import</span> <span class="n">Blog</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Beatles Blog&#39;</span><span class="p">,</span> <span class="n">tagline</span><span class="o">=</span><span class="s1">&#39;All the latest Beatles news.&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>这在幕后执行了 <code class="docutils literal notranslate"><span class="pre">INSERT</span></code> SQL 语句。Django 在你显式调用 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 才操作数据库。</p>
<p><a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 方法没有返回值。</p>
<div class="admonition seealso">
<p class="first admonition-title">参见</p>
<p><a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 接受很多此处未介绍的高级选项。参考文档 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 获取完整细节。</p>
<p class="last">要一步创建并保存一个对象，使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.create" title="django.db.models.query.QuerySet.create"><code class="xref py py-meth docutils literal notranslate"><span class="pre">create()</span></code></a> 方法。</p>
</div>
</div>
<div class="section" id="s-saving-changes-to-objects">
<span id="saving-changes-to-objects"></span><h2>将修改保存至对象<a class="headerlink" href="#saving-changes-to-objects" title="永久链接至标题">¶</a></h2>
<p>要将修改保存至数据库中已有的某个对象，使用 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a>。</p>
<p>有一个已被存入数据库中的 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 实例 <code class="docutils literal notranslate"><span class="pre">b5</span></code>，本例将其改名，并在数据库中更新其记录:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">b5</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;New name&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b5</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>这在幕后执行了 <code class="docutils literal notranslate"><span class="pre">UPDATE</span></code> SQL 语句。Django 在你显示调用 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 后才操作数据库。</p>
<div class="section" id="s-saving-foreignkey-and-manytomanyfield-fields">
<span id="saving-foreignkey-and-manytomanyfield-fields"></span><h3>保存 <code class="docutils literal notranslate"><span class="pre">ForeignKey</span></code> 和 <code class="docutils literal notranslate"><span class="pre">ManyToManyField</span></code> 字段<a class="headerlink" href="#saving-foreignkey-and-manytomanyfield-fields" title="永久链接至标题">¶</a></h3>
<p>更新 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 字段的方式与保存普通字段的方式相同——只需将正确类型的实例分配给相关字段。本例为 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 类的实例 <code class="docutils literal notranslate"><span class="pre">entry</span></code> 更新了 <code class="docutils literal notranslate"><span class="pre">blog</span></code> 属性，假设 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 的实例均已保存在数据库中（因此能在下面检索它们）：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">blog.models</span> <span class="kn">import</span> <span class="n">Blog</span><span class="p">,</span> <span class="n">Entry</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">entry</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">cheese_blog</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Cheddar Talk&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">entry</span><span class="o">.</span><span class="n">blog</span> <span class="o">=</span> <span class="n">cheese_blog</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">entry</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>更新 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a> 字段有点不同——在字段上使用 <a class="reference internal" href="../../ref/models/relations.html#django.db.models.fields.related.RelatedManager.add" title="django.db.models.fields.related.RelatedManager.add"><code class="xref py py-meth docutils literal notranslate"><span class="pre">add()</span></code></a> 方法为关联关系添加一条记录。本例将 <code class="docutils literal notranslate"><span class="pre">Author</span></code> 实例 <code class="docutils literal notranslate"><span class="pre">joe</span></code> 添加至 <code class="docutils literal notranslate"><span class="pre">entry</span></code> 对象:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">blog.models</span> <span class="kn">import</span> <span class="n">Author</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">joe</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Joe&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">entry</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">joe</span><span class="p">)</span>
</pre></div>
</div>
<p>要一次添加多行记录至 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a> 字段，在一次调用 <a class="reference internal" href="../../ref/models/relations.html#django.db.models.fields.related.RelatedManager.add" title="django.db.models.fields.related.RelatedManager.add"><code class="xref py py-meth docutils literal notranslate"><span class="pre">add()</span></code></a> 时传入多个参数，像这样:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">john</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;John&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">paul</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Paul&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">george</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;George&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ringo</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Ringo&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">entry</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">john</span><span class="p">,</span> <span class="n">paul</span><span class="p">,</span> <span class="n">george</span><span class="p">,</span> <span class="n">ringo</span><span class="p">)</span>
</pre></div>
</div>
<p>Django 会在添加或指定错误类型的对象时报错。</p>
</div>
</div>
<div class="section" id="s-retrieving-objects">
<span id="s-id1"></span><span id="retrieving-objects"></span><span id="id1"></span><h2>检索对象<a class="headerlink" href="#retrieving-objects" title="永久链接至标题">¶</a></h2>
<p>要从数据库检索对象，要通过模型类的 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 构建一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>。</p>
<p>一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 代表来自数据库中对象的一个集合。它可以有 0 个，1 个或者多个 <em>filters</em>. Filters，可以根据给定参数缩小查询结果量。在 SQL 的层面上， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 对应 <code class="docutils literal notranslate"><span class="pre">SELECT</span></code> 语句，而*filters*对应类似 <code class="docutils literal notranslate"><span class="pre">WHERE</span></code> 或 <code class="docutils literal notranslate"><span class="pre">LIMIT</span></code> 的限制子句。</p>
<p>你能通过模型的 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 获取 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>。每个模型至少有一个 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a>，默认名称是 <a class="reference internal" href="../../ref/models/class.html#django.db.models.Model.objects" title="django.db.models.Model.objects"><code class="xref py py-attr docutils literal notranslate"><span class="pre">objects</span></code></a>。像这样直接通过模型类使用它:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span>
<span class="go">&lt;django.db.models.manager.Manager object at ...&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Foo&#39;</span><span class="p">,</span> <span class="n">tagline</span><span class="o">=</span><span class="s1">&#39;Bar&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">objects</span>
<span class="go">Traceback:</span>
<span class="go">    ...</span>
<span class="go">AttributeError: &quot;Manager isn&#39;t accessible via Blog instances.&quot;</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last"><code class="docutils literal notranslate"><span class="pre">Managers</span></code> 只能通过模型类访问，而不是通过模型实例，目的是强制分离 “表级” 操作和 “行级” 操作。</p>
</div>
<p><a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 是模型的 <code class="docutils literal notranslate"><span class="pre">QuerySets</span></code> 主要来源。例如 <code class="docutils literal notranslate"><span class="pre">Blog.objects.all()</span></code> 返回了一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，后者包含了数据库中所有的 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 对象。</p>
<div class="section" id="s-retrieving-all-objects">
<span id="retrieving-all-objects"></span><h3>检索全部对象<a class="headerlink" href="#retrieving-all-objects" title="永久链接至标题">¶</a></h3>
<p>从数据库中检索对象最简单的方式就是检索全部。为此，在 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 上调用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.all" title="django.db.models.query.QuerySet.all"><code class="xref py py-meth docutils literal notranslate"><span class="pre">all()</span></code></a> 方法:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">all_entries</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>方法 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.all" title="django.db.models.query.QuerySet.all"><code class="xref py py-meth docutils literal notranslate"><span class="pre">all()</span></code></a> 返回了一个包含数据库中所有对象的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 对象。</p>
</div>
<div class="section" id="s-retrieving-specific-objects-with-filters">
<span id="retrieving-specific-objects-with-filters"></span><h3>通过过滤器检索指定对象<a class="headerlink" href="#retrieving-specific-objects-with-filters" title="永久链接至标题">¶</a></h3>
<p><a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.all" title="django.db.models.query.QuerySet.all"><code class="xref py py-meth docutils literal notranslate"><span class="pre">all()</span></code></a> 返回的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 包含了数据表中所有的对象。虽然，大多数情况下，你只需要完整对象集合的一个子集。</p>
<p>要创建一个这样的子集，你需要通过添加过滤条件精炼原始 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>。两种最常见的精炼 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的方式是：</p>
<dl class="docutils">
<dt><code class="docutils literal notranslate"><span class="pre">filter(**kwargs)</span></code></dt>
<dd>返回一个新的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，包含的对象满足给定查询参数。</dd>
<dt><code class="docutils literal notranslate"><span class="pre">exclude(**kwargs)</span></code></dt>
<dd>返回一个新的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，包含的对象 <em>不</em> 满足给定查询参数。</dd>
</dl>
<p>查询参数（<code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>）应该符合下面的 <a class="reference internal" href="#field-lookups">Field lookups</a> 的要求。</p>
<p>例如，要包含获取 2006 年的博客条目（entries blog）的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，像这样使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="mi">2006</span><span class="p">)</span>
</pre></div>
</div>
<p>通过默认管理器类也一样:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="mi">2006</span><span class="p">)</span>
</pre></div>
</div>
<div class="section" id="s-chaining-filters">
<span id="s-id2"></span><span id="chaining-filters"></span><span id="id2"></span><h4>链式过滤器<a class="headerlink" href="#chaining-filters" title="永久链接至标题">¶</a></h4>
<p>精炼 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的结果本身还是一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，所以能串联精炼过程。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
<span class="gp">... </span>    <span class="n">headline__startswith</span><span class="o">=</span><span class="s1">&#39;What&#39;</span>
<span class="gp">... </span><span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span>
<span class="gp">... </span>    <span class="n">pub_date__gte</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">today</span><span class="p">()</span>
<span class="gp">... </span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
<span class="gp">... </span>    <span class="n">pub_date__gte</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
<span class="gp">... </span><span class="p">)</span>
</pre></div>
</div>
<p>这个先获取包含数据库所有条目（entry）的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，然后排除一些，再进入另一个过滤器。最终的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 包含标题以 &quot;What&quot; 开头的，发布日期介于 2005 年 1 月 30 日与今天之间的所有条目。</p>
</div>
<div class="section" id="s-filtered-querysets-are-unique">
<span id="s-id3"></span><span id="filtered-querysets-are-unique"></span><span id="id3"></span><h4>每个 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 都是唯一的<a class="headerlink" href="#filtered-querysets-are-unique" title="永久链接至标题">¶</a></h4>
<p>每次精炼一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，你就会获得一个全新的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，后者与前者毫无关联。每次精炼都会创建一个单独的、不同的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，能被存储，使用和复用。</p>
<p>举例：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">q1</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">headline__startswith</span><span class="o">=</span><span class="s2">&quot;What&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q2</span> <span class="o">=</span> <span class="n">q1</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="n">pub_date__gte</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">today</span><span class="p">())</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q3</span> <span class="o">=</span> <span class="n">q1</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__gte</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">today</span><span class="p">())</span>
</pre></div>
</div>
<p>这三个 <code class="docutils literal notranslate"><span class="pre">QuerySets</span></code> 是独立的。第一个是基础 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，包含了所有标题以 &quot;What&quot; 开头的条目。第二个是第一个的子集，带有额外条件，排除了 <code class="docutils literal notranslate"><span class="pre">pub_date</span></code> 是今天和今天之后的所有记录。第三个是第一个的子集，带有额外条件，只筛选 <code class="docutils literal notranslate"><span class="pre">pub_date</span></code> 是今天或未来的所有记录。最初的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> (<code class="docutils literal notranslate"><span class="pre">q1</span></code>) 不受筛选操作影响。</p>
</div>
<div class="section" id="s-querysets-are-lazy">
<span id="s-id4"></span><span id="querysets-are-lazy"></span><span id="id4"></span><h4><code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 是惰性的<a class="headerlink" href="#querysets-are-lazy" title="永久链接至标题">¶</a></h4>
<p><code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 是惰性的 —— 创建 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 并不会引发任何数据库活动。你可以将一整天的过滤器都堆积在一起，Django 只会在 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 被 <em>计算</em> 时执行查询操作。来瞄一眼这个例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">headline__startswith</span><span class="o">=</span><span class="s2">&quot;What&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__lte</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">today</span><span class="p">())</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="n">body_text__icontains</span><span class="o">=</span><span class="s2">&quot;food&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
</pre></div>
</div>
<p>虽然这看起来像是三次数据库操作，实际上只在最后一行 (<code class="docutils literal notranslate"><span class="pre">print(q)</span></code>) 做了一次。一般来说， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的结果直到你 “要使用” 时才会从数据库中拿出。当你要用时，才通过数据库 <em>计算</em> 出 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>。关于何时才真的执行计算的更多细节，参考 <a class="reference internal" href="../../ref/models/querysets.html#when-querysets-are-evaluated"><span class="std std-ref">什么时候 QuerySet 被执行</span></a>。</p>
</div>
</div>
<div class="section" id="s-retrieving-a-single-object-with-get">
<span id="s-retrieving-single-object-with-get"></span><span id="retrieving-a-single-object-with-get"></span><span id="retrieving-single-object-with-get"></span><h3>用 <code class="docutils literal notranslate"><span class="pre">get()</span></code> 检索单个对象<a class="headerlink" href="#retrieving-a-single-object-with-get" title="永久链接至标题">¶</a></h3>
<p><a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 总是返回一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，即便只有一个对象满足查询条件 —— 这种情况下， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 只包含了一个元素。</p>
<p>若你知道只会有一个对象满足查询条件，你可以在 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 上使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a> 方法，它会直接返回这个对象:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">one_entry</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>你可以对 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a> 使用与 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 类似的所有查询表达式 —— 同样的，参考下面的 <a class="reference internal" href="#field-lookups">Field lookups</a>。</p>
<p>注意， 使用切片 <code class="docutils literal notranslate"><span class="pre">[0]</span></code> 时的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a> 和 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 有点不同。如果没有满足查询条件的结果， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a> 会抛出一个 <code class="docutils literal notranslate"><span class="pre">DoesNotExist</span></code> 异常。该异常是执行查询的模型类的一个属性 —— 所有，上述代码中，若没有哪个 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 对象的主键是 1，Django 会抛出 <code class="docutils literal notranslate"><span class="pre">Entry.DoesNotExist</span></code>。</p>
<p>类似了，Django 会在有不止一个记录满足 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a> 查询条件时发出警告。这时，Django 会抛出 <a class="reference internal" href="../../ref/exceptions.html#django.core.exceptions.MultipleObjectsReturned" title="django.core.exceptions.MultipleObjectsReturned"><code class="xref py py-exc docutils literal notranslate"><span class="pre">MultipleObjectsReturned</span></code></a>，这同样也是模型类的一个属性。</p>
</div>
<div class="section" id="s-other-queryset-methods">
<span id="other-queryset-methods"></span><h3>其它 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 方法<a class="headerlink" href="#other-queryset-methods" title="永久链接至标题">¶</a></h3>
<p>大多数情况下，你会在需要从数据库中检索对象时使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.all" title="django.db.models.query.QuerySet.all"><code class="xref py py-meth docutils literal notranslate"><span class="pre">all()</span></code></a>， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a>， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 和 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.exclude" title="django.db.models.query.QuerySet.exclude"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code></a>。然而，这样远远不够；完整的各种 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 方法请参阅 <a class="reference internal" href="../../ref/models/querysets.html#queryset-api"><span class="std std-ref">QuerySet&nbsp;API 参考</span></a>。</p>
</div>
<div class="section" id="s-limiting-querysets">
<span id="s-id5"></span><span id="limiting-querysets"></span><span id="id5"></span><h3>限制 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 条目数<a class="headerlink" href="#limiting-querysets" title="永久链接至标题">¶</a></h3>
<p>利用 Python 的数组切片语法将 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 切成指定长度。这等价于 SQL 的 <code class="docutils literal notranslate"><span class="pre">LIMIT</span></code> 和 <code class="docutils literal notranslate"><span class="pre">OFFSET</span></code> 子句。</p>
<p>例如，这将返回前 5 个对象 (<code class="docutils literal notranslate"><span class="pre">LIMIT</span> <span class="pre">5</span></code>):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()[:</span><span class="mi">5</span><span class="p">]</span>
</pre></div>
</div>
<p>这会返回第 6 至第 10 个对象 (<code class="docutils literal notranslate"><span class="pre">OFFSET</span> <span class="pre">5</span> <span class="pre">LIMIT</span> <span class="pre">5</span></code>):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()[</span><span class="mi">5</span><span class="p">:</span><span class="mi">10</span><span class="p">]</span>
</pre></div>
</div>
<p>不支持负索引 (例如 <code class="docutils literal notranslate"><span class="pre">Entry.objects.all()[-1]</span></code>)</p>
<p>一般情况下， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的切片返回一个新的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> —— 其并未执行查询。一个特殊情况是使用了的 Python 切片语法的 “步长”。例如，这将会实际的执行查询命令，为了获取从前 10 个对象中，每隔一个抽取的对象组成的列表:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()[:</span><span class="mi">10</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span>
</pre></div>
</div>
<p>由于对 queryset 切片工作方式的模糊性，禁止对其进行进一步的排序或过滤。</p>
<p>要检索 <em>单个</em> 对象而不是一个列表时（例如 <code class="docutils literal notranslate"><span class="pre">SELECT</span> <span class="pre">foo</span> <span class="pre">FROM</span> <span class="pre">bar</span> <span class="pre">LIMIT</span> <span class="pre">1</span></code>），请使用索引，而不是切片。例如，这会返回按标题字母排序后的第一个 <code class="docutils literal notranslate"><span class="pre">Entry</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">&#39;headline&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</pre></div>
</div>
<p>这大致等价于:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">&#39;headline&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">:</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
</pre></div>
</div>
<p>然而，注意一下，若没有对象满足给定条件，前者会抛出 <code class="docutils literal notranslate"><span class="pre">IndexError</span></code>，而后者会抛出 <code class="docutils literal notranslate"><span class="pre">DoesNotExist</span></code>。参考 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a> 获取更多细节。</p>
</div>
<div class="section" id="s-field-lookups">
<span id="s-field-lookups-intro"></span><span id="field-lookups"></span><span id="field-lookups-intro"></span><h3>字段查询<a class="headerlink" href="#field-lookups" title="永久链接至标题">¶</a></h3>
<p>字段查询即你如何制定 SQL <code class="docutils literal notranslate"><span class="pre">WHERE</span></code> 子句。它们以关键字参数的形式传递给 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 方法 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a>， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.exclude" title="django.db.models.query.QuerySet.exclude"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code></a> 和 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a>。</p>
<p>基本的查询关键字参数遵照 <code class="docutils literal notranslate"><span class="pre">field__lookuptype=value</span></code>。（有个双下划线）。例如:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__lte</span><span class="o">=</span><span class="s1">&#39;2006-01-01&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>转换为 SQL 语句大致如下：</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">blog_entry</span> <span class="k">WHERE</span> <span class="n">pub_date</span> <span class="o">&lt;=</span> <span class="s1">&#39;2006-01-01&#39;</span><span class="p">;</span>
</pre></div>
</div>
<div class="admonition-how-this-is-possible admonition">
<p class="first admonition-title">这是怎么做到的</p>
<p class="last">Python 能定义可接受任意数量 name-value 参数的函数，参数名和值均在运行时计算。更多信息，请参考官方 Python 教程中的 <a class="reference external" href="https://docs.python.org/3/tutorial/controlflow.html#tut-keywordargs" title="(在 Python v3.10)"><span>Keyword Arguments</span></a>。</p>
</div>
<p>查询子句中指定的字段必须是模型的一个字段名。不过也有个例外，在 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 中，你可以指定以 <code class="docutils literal notranslate"><span class="pre">_id</span></code> 为后缀的字段名。这种情况下，value 参数需要包含 foreign 模型的主键的原始值。例子：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog_id</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
</pre></div>
</div>
<p>若你传入了无效的关键字参数，查询函数会抛出 <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>。</p>
<p>数据库 API 支持两套查询类型；完整参考文档位于 <a class="reference internal" href="../../ref/models/querysets.html#field-lookups"><span class="std std-ref">字段查询参考</span></a>。为了让你了解能干啥，以下是一些常见的查询：</p>
<dl class="docutils">
<dt><a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-exact"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">exact</span></code></a></dt>
<dd><p class="first">一个 &quot;exact&quot; 匹配的例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">headline__exact</span><span class="o">=</span><span class="s2">&quot;Cat bites dog&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>会生成这些 SQL：</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">SELECT</span> <span class="p">...</span> <span class="k">WHERE</span> <span class="n">headline</span> <span class="o">=</span> <span class="s1">&#39;Cat bites dog&#39;</span><span class="p">;</span>
</pre></div>
</div>
<p>若你为提供查询类型 —— 也就说，若关键字参数未包含双下划线 —— 查询类型会被指定为 <code class="docutils literal notranslate"><span class="pre">exact</span></code>。</p>
<p>例如，以下两条语句是等价的:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">id__exact</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>  <span class="c1"># Explicit form</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>         <span class="c1"># __exact is implied</span>
</pre></div>
</div>
<p class="last">这是为了方便，因为 <code class="docutils literal notranslate"><span class="pre">exact</span></code> 查询是最常见的。</p>
</dd>
<dt><a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-iexact"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">iexact</span></code></a></dt>
<dd><p class="first">不分大小写的匹配，查询语句:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name__iexact</span><span class="o">=</span><span class="s2">&quot;beatles blog&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p class="last">会匹配标题为 <code class="docutils literal notranslate"><span class="pre">&quot;Beatles</span> <span class="pre">Blog&quot;</span></code>， <code class="docutils literal notranslate"><span class="pre">&quot;beatles</span> <span class="pre">blog&quot;</span></code>， 甚至 <code class="docutils literal notranslate"><span class="pre">&quot;BeAtlES</span> <span class="pre">blOG&quot;</span></code> 的 <code class="docutils literal notranslate"><span class="pre">Blog</span></code>。</p>
</dd>
<dt><a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-contains"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">contains</span></code></a></dt>
<dd><p class="first">大小写敏感的包含测试。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>粗略地转为 SQL：</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">SELECT</span> <span class="p">...</span> <span class="k">WHERE</span> <span class="n">headline</span> <span class="k">LIKE</span> <span class="s1">&#39;%Lennon%&#39;</span><span class="p">;</span>
</pre></div>
</div>
<p>注意这将匹配标题 <code class="docutils literal notranslate"><span class="pre">'Today</span> <span class="pre">Lennon</span> <span class="pre">honored'</span></code>，而不是 <code class="docutils literal notranslate"><span class="pre">'today</span> <span class="pre">lennon</span> <span class="pre">honored'</span></code>。</p>
<p class="last">这也有个大小写不敏感的版本， <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-icontains"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">icontains</span></code></a>。</p>
</dd>
<dt><a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-startswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">startswith</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-endswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">endswith</span></code></a></dt>
<dd>以……开头和以……结尾的查找。当然也有大小写不敏感的版本，名为 <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-istartswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">istartswith</span></code></a> 和 <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-iendswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">iendswith</span></code></a>。</dd>
</dl>
<p>同样，这只介绍了皮毛。完整的参考能在 <a class="reference internal" href="../../ref/models/querysets.html#field-lookups"><span class="std std-ref">field&nbsp;查询参考</span></a> 找到。</p>
</div>
<div class="section" id="s-lookups-that-span-relationships">
<span id="s-id6"></span><span id="lookups-that-span-relationships"></span><span id="id6"></span><h3>跨关系查询<a class="headerlink" href="#lookups-that-span-relationships" title="永久链接至标题">¶</a></h3>
<p>Django 提供了一种强大而直观的方式来“追踪”查询中的关系，在幕后自动为你处理 SQL <code class="docutils literal notranslate"><span class="pre">JOIN</span></code> 关系。为了跨越关系，跨模型使用关联字段名，字段名由双下划线分割，直到拿到想要的字段。</p>
<p>本例检索出所有的 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 对象，其 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 的 <code class="docutils literal notranslate"><span class="pre">name</span></code> 为 <code class="docutils literal notranslate"><span class="pre">'Beatles</span> <span class="pre">Blog'</span></code> ：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog__name</span><span class="o">=</span><span class="s1">&#39;Beatles Blog&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>跨域的深度随你所想。</p>
<p>It works backwards, too. While it <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey.related_query_name" title="django.db.models.ForeignKey.related_query_name"><code class="xref py py-attr docutils literal notranslate"><span class="pre">can</span> <span class="pre">be</span> <span class="pre">customized</span></code></a>, by default you refer to a &quot;reverse&quot;
relationship in a lookup using the lowercase name of the model.</p>
<p>本例检索的所有 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 对象均拥有少一个 <code class="docutils literal notranslate"><span class="pre">标题</span></code> 含有 <code class="docutils literal notranslate"><span class="pre">'Lennon'</span></code> 的条目:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>如果你在跨多个关系进行筛选，而某个中间模型的没有满足筛选条件的值，Django  会将它当做一个空的（所有值都是 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>）但是有效的对象。这样就意味着不会抛出错误。例如，在这个过滤器中:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__authors__name</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>（假设有个关联的 <code class="docutils literal notranslate"><span class="pre">Author</span></code> 模型），若某项条目没有任何关联的 <code class="docutils literal notranslate"><span class="pre">author</span></code>，它会被视作没有关联的 <code class="docutils literal notranslate"><span class="pre">name</span></code>，而不是因为缺失 <code class="docutils literal notranslate"><span class="pre">author</span></code> 而抛出错误。大多数情况下，这就是你期望的。唯一可能使你迷惑的场景是在使用 <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-isnull"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">isnull</span></code></a> 时。因此:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__authors__name__isnull</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>将会返回 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 对象，包含 <code class="docutils literal notranslate"><span class="pre">author</span></code> 的 <code class="docutils literal notranslate"><span class="pre">name</span></code> 为空的对象，以及那些 <code class="docutils literal notranslate"><span class="pre">entry</span></code> 的 <code class="docutils literal notranslate"><span class="pre">author</span></code> 为空的对象。若你不想要后面的对象，你可以这样写:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__authors__isnull</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">entry__authors__name__isnull</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<div class="section" id="s-spanning-multi-valued-relationships">
<span id="spanning-multi-valued-relationships"></span><h4>跨多值关联<a class="headerlink" href="#spanning-multi-valued-relationships" title="永久链接至标题">¶</a></h4>
<p>当基于 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a> 或反向 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 筛选某对象时，你可能对两种不同类型的过滤器感兴趣。假设 <code class="docutils literal notranslate"><span class="pre">Blog</span></code>/<code class="docutils literal notranslate"><span class="pre">Entry</span></code> 关联关系（<code class="docutils literal notranslate"><span class="pre">Blog</span></code> 对 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 是一种一对多关联关系）。我们可能对那些条目标题同时含有 <em>&quot;Lennon&quot;</em> 且发布于 2008 年的博客感兴趣。或者，我们可能想找到那些条目标题包含 <em>&quot;Lennon&quot;</em> 或发布于 2008 的博客。由于多个 <code class="docutils literal notranslate"><span class="pre">Entry``能同时关联至一个</span> <span class="pre">``Blog</span></code>，两种查询都是可行的，且在某些场景下非常有用。</p>
<p>同样的场景也发生在 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a>。例如，若有个 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 拥有一个叫做 <code class="docutils literal notranslate"><span class="pre">tags</span></code> 的 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a>，要从关联至 tags 中的条目中找到名为 <em>&quot;music&quot;</em> 和 <em>&quot;bands&quot;</em> 的条目，或要找到某个标签名为 <em>&quot;music&quot;</em> 且状态为 <em>&quot;public&quot;</em> 的条目。</p>
<p>要处理这两种情况，Django 有一套统一的方式处理 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 调用。配置给某次 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 的所有条件会在调用时同时生效，筛选出满足条件的项目。连续的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 调用进一步限制了对象结果集，但对于多值关联来说，限制条件作用于链接至主模型的对象，而不一定是那些被前置 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 调用筛选的对象。</p>
<p>这听起来可能有点迷糊，所以需要一个例子来解释一下。要筛选出所有关联条目同时满足标题含有 <em>&quot;Lennon&quot;</em> 且发布于 2008 （同一个条目，同时满足两个条件）年的博客，我们会这样写:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">,</span> <span class="n">entry__pub_date__year</span><span class="o">=</span><span class="mi">2008</span><span class="p">)</span>
</pre></div>
</div>
<p>要筛选所有条目标题包含 <em>&quot;Lennon&quot;</em> 或条目发布于 2008 年的博客，我们会这样写:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">entry__pub_date__year</span><span class="o">=</span><span class="mi">2008</span><span class="p">)</span>
</pre></div>
</div>
<p>假设只有一个博客，拥有的条目同时满足标题含有 <em>&quot;Lennon&quot;</em> 且发布于 2008 年，但是发布于 2008 年的条目的标题均不含有 <em>&quot;Lennon&quot;</em>。第一项查询不会返回任何博客，而第二项查询会返回此博客。</p>
<p>在第二个例子中，第一个过滤器限制结果集为那些关联了标题包含 <em>&quot;Lennon&quot;</em> 的条目的博客。第二个过滤器进一步要求结果集中的博客要发布于 2008 年。第二个过滤器筛选的条目与第一个过滤器筛选的可能不尽相同。我们是用过滤器语句筛选 <code class="docutils literal notranslate"><span class="pre">Blog</span></code>，而不是 <code class="docutils literal notranslate"><span class="pre">Entry</span></code>。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p><a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 的查询行为会跨越多值关联，就像前文说的那样，并不与 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.exclude" title="django.db.models.query.QuerySet.exclude"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code></a> 相同。相反，一次 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.exclude" title="django.db.models.query.QuerySet.exclude"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code></a> 调用的条件并不需要指向同一项目。</p>
<p>例如，以下查询会排除那些关联条目标题包含 <em>&quot;Lennon&quot;</em> 且发布于 2008 年的博客:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span>
    <span class="n">entry__headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">,</span>
    <span class="n">entry__pub_date__year</span><span class="o">=</span><span class="mi">2008</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>但是，与 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 的行为不同，其并不会限制博客同时满足这两种条件。要这么做的话，也就是筛选出所有条目标题不带 <em>&quot;Lennon&quot;</em> 且发布年不是 2008 的博客，你需要做两次查询:</p>
<div class="last highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span>
    <span class="n">entry__in</span><span class="o">=</span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
        <span class="n">headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">,</span>
        <span class="n">pub_date__year</span><span class="o">=</span><span class="mi">2008</span><span class="p">,</span>
    <span class="p">),</span>
<span class="p">)</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="s-filters-can-reference-fields-on-the-model">
<span id="s-using-f-expressions-in-filters"></span><span id="filters-can-reference-fields-on-the-model"></span><span id="using-f-expressions-in-filters"></span><h3>过滤器可以为模型指定字段<a class="headerlink" href="#filters-can-reference-fields-on-the-model" title="永久链接至标题">¶</a></h3>
<p>在之前的例子中，我们已经构建过的 <code class="docutils literal notranslate"><span class="pre">filter</span></code> 都是将模型字段值与常量做比较。但是，要怎么做才能将模型字段值与同一模型中的另一字段做比较呢？</p>
<p>Django 提供了 <a class="reference internal" href="../../ref/models/expressions.html#django.db.models.F" title="django.db.models.F"><code class="xref py py-class docutils literal notranslate"><span class="pre">F</span> <span class="pre">表达式</span></code></a> 实现这种比较。 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 的实例充当查询中的模型字段的引用。这些引用可在查询过滤器中用于在同一模型实例中比较两个不同的字段。</p>
<p>例如，要查出所有评论数大于 pingbacks 的博客条目，我们构建了一个 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象，指代 pingback 的数量，然后在查询中使用该 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">F</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">number_of_comments__gt</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;number_of_pingbacks&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>Django 支持对 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象进行加、减、乘、除、求余和次方，另一操作数既可以是常量，也可以是其它 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象。要找到那些评论数两倍于 pingbacks 的博客条目，我们这样修改查询条件:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">number_of_comments__gt</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;number_of_pingbacks&#39;</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span>
</pre></div>
</div>
<p>要找出所有评分低于 pingback 和评论总数之和的条目，修改查询条件:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">rating__lt</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;number_of_comments&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="n">F</span><span class="p">(</span><span class="s1">&#39;number_of_pingbacks&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>你也能用双下划线在 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象中通过关联关系查询。带有双下划线的 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象将引入访问关联对象所需的任何连接。例如，要检索出所有作者名与博客名相同的博客，这样修改查询条件:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">authors__name</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;blog__name&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>对于 date 和 date/time 字段，你可以加上或减去一个 <a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.timedelta" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">timedelta</span></code></a> 对象。以下会返回所有发布 3 天后被修改的条目:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">timedelta</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">mod_date__gt</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;pub_date&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">3</span><span class="p">))</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象通过 <code class="docutils literal notranslate"><span class="pre">.bitand()</span></code>， <code class="docutils literal notranslate"><span class="pre">.bitor()</span></code>， <code class="docutils literal notranslate"><span class="pre">.bitxor()</span></code>，<code class="docutils literal notranslate"><span class="pre">.bitrightshift()</span></code> 和 <code class="docutils literal notranslate"><span class="pre">.bitleftshift()</span></code> 支持位操作。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;somefield&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">bitand</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition-oracle admonition">
<p class="first admonition-title">Oracle</p>
<p class="last">Oracle 不支持按位 XOR 操作。</p>
</div>
<div class="versionchanged">
<span class="title">Changed in Django 3.1:</span> <p>已添加对 <code class="docutils literal notranslate"><span class="pre">.bitxor()</span></code> 的支持。</p>
</div>
</div>
<div class="section" id="s-expressions-can-reference-transforms">
<span id="s-using-transforms-in-expressions"></span><span id="expressions-can-reference-transforms"></span><span id="using-transforms-in-expressions"></span><h3>Expressions can reference transforms<a class="headerlink" href="#expressions-can-reference-transforms" title="永久链接至标题">¶</a></h3>
<div class="versionadded">
<span class="title">New in Django 3.2.</span> </div>
<p>Django supports using transforms in expressions.</p>
<p>For example, to find all <code class="docutils literal notranslate"><span class="pre">Entry</span></code> objects published in the same year as they
were last modified:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;mod_date__year&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>To find the earliest year an entry was published, we can issue the query:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">aggregate</span><span class="p">(</span><span class="n">first_published_year</span><span class="o">=</span><span class="n">Min</span><span class="p">(</span><span class="s1">&#39;pub_date__year&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>This example finds the value of the highest rated entry and the total number
of comments on all entries for each year:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">values</span><span class="p">(</span><span class="s1">&#39;pub_date__year&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
<span class="gp">... </span>    <span class="n">top_rating</span><span class="o">=</span><span class="n">Subquery</span><span class="p">(</span>
<span class="gp">... </span>        <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
<span class="gp">... </span>            <span class="n">pub_date__year</span><span class="o">=</span><span class="n">OuterRef</span><span class="p">(</span><span class="s1">&#39;pub_date__year&#39;</span><span class="p">),</span>
<span class="gp">... </span>        <span class="p">)</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">&#39;-rating&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">values</span><span class="p">(</span><span class="s1">&#39;rating&#39;</span><span class="p">)[:</span><span class="mi">1</span><span class="p">]</span>
<span class="gp">... </span>    <span class="p">),</span>
<span class="gp">... </span>    <span class="n">total_comments</span><span class="o">=</span><span class="n">Sum</span><span class="p">(</span><span class="s1">&#39;number_of_comments&#39;</span><span class="p">),</span>
<span class="gp">... </span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-the-pk-lookup-shortcut">
<span id="the-pk-lookup-shortcut"></span><h3>主键 (<code class="docutils literal notranslate"><span class="pre">pk</span></code>) 查询快捷方式<a class="headerlink" href="#the-pk-lookup-shortcut" title="永久链接至标题">¶</a></h3>
<p>出于方便的目的，Django 提供了一种 <code class="docutils literal notranslate"><span class="pre">pk</span></code> 查询快捷方式， <code class="docutils literal notranslate"><span class="pre">pk</span></code> 表示主键 &quot;primary key&quot;。</p>
<p>示例 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 模型中，主键是 <code class="docutils literal notranslate"><span class="pre">id</span></code> 字段，所以这 3 个语句是等效的:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">id__exact</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span> <span class="c1"># Explicit form</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span> <span class="c1"># __exact is implied</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span> <span class="c1"># pk implies id__exact</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">pk</span></code> 的使用并不仅限于 <code class="docutils literal notranslate"><span class="pre">__exact</span></code> 查询——任何的查询项都能接在 <code class="docutils literal notranslate"><span class="pre">pk</span></code> 后面，执行对模型主键的查询:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Get blogs entries with id 1, 4 and 7</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pk__in</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">7</span><span class="p">])</span>

<span class="c1"># Get all blog entries with id &gt; 14</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pk__gt</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">pk</span></code> 查找也支持跨连接。例如，以下 3 个语句是等效的:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog__id__exact</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># Explicit form</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog__id</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>        <span class="c1"># __exact is implied</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog__pk</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>        <span class="c1"># __pk implies __id__exact</span>
</pre></div>
</div>
</div>
<div class="section" id="s-escaping-percent-signs-and-underscores-in-like-statements">
<span id="escaping-percent-signs-and-underscores-in-like-statements"></span><h3>在 <code class="docutils literal notranslate"><span class="pre">LIKE</span></code> 语句中转义百分号和下划线<a class="headerlink" href="#escaping-percent-signs-and-underscores-in-like-statements" title="永久链接至标题">¶</a></h3>
<p>等效于 <code class="docutils literal notranslate"><span class="pre">LIKE</span></code> SQL 语句的字段查询子句 (<code class="docutils literal notranslate"><span class="pre">iexact</span></code>， <code class="docutils literal notranslate"><span class="pre">contains</span></code>， <code class="docutils literal notranslate"><span class="pre">icontains</span></code>， <code class="docutils literal notranslate"><span class="pre">startswith</span></code>， <code class="docutils literal notranslate"><span class="pre">istartswith</span></code>， <code class="docutils literal notranslate"><span class="pre">endswith</span></code> 和 <code class="docutils literal notranslate"><span class="pre">iendswith</span></code>) 会将 <code class="docutils literal notranslate"><span class="pre">LIKE</span></code> 语句中有特殊用途的两个符号，即百分号和下划线自动转义。（在 <code class="docutils literal notranslate"><span class="pre">LIKE</span></code> 语句中，百分号匹配多个任意字符，而下划线匹配一个任意字符。）</p>
<p>这意味着事情应该直观地工作，这样抽象就不会泄露。例如，要检索所有包含百分号的条目，就像对待其它字符一样使用百分号：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">headline__contains</span><span class="o">=</span><span class="s1">&#39;%&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Django 为你小心处理了引号；生成的 SQL 语句看起来像这样：</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">SELECT</span> <span class="p">...</span> <span class="k">WHERE</span> <span class="n">headline</span> <span class="k">LIKE</span> <span class="s1">&#39;%\%%&#39;</span><span class="p">;</span>
</pre></div>
</div>
<p>同样的处理也包括下划线。百分号和下划线都为你自动处理，你无需担心。</p>
</div>
<div class="section" id="s-caching-and-querysets">
<span id="s-id7"></span><span id="caching-and-querysets"></span><span id="id7"></span><h3>缓存和 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code><a class="headerlink" href="#caching-and-querysets" title="永久链接至标题">¶</a></h3>
<p>每个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 都带有缓存，尽量减少数据库访问。理解它是如何工作的能让你编写更高效的代码。</p>
<p>新创建的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 缓存是空的。一旦要计算 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的值，就会执行数据查询，随后，Django 就会将查询结果保存在 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的缓存中，并返回这些显式请求的缓存（例如，下一个元素，若 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 正在被迭代）。后续针对 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的计算会复用缓存结果。</p>
<p>牢记这种缓存行为，在你错误使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 时可能会被它咬一下。例如，以下会创建两个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，计算它们，丢掉它们:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="n">e</span><span class="o">.</span><span class="n">headline</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="n">e</span><span class="o">.</span><span class="n">pub_date</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()])</span>
</pre></div>
</div>
<p>这意味着同样的数据库查询会被执行两次，实际加倍了数据库负载。同时，有可能这两个列表不包含同样的记录，因为在两次请求间，可能有 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 被添加或删除了。</p>
<p>要避免此问题，保存 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 并复用它:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">queryset</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="n">p</span><span class="o">.</span><span class="n">headline</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">queryset</span><span class="p">])</span> <span class="c1"># Evaluate the query set.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="n">p</span><span class="o">.</span><span class="n">pub_date</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">queryset</span><span class="p">])</span> <span class="c1"># Re-use the cache from the evaluation.</span>
</pre></div>
</div>
<div class="section" id="s-when-querysets-are-not-cached">
<span id="when-querysets-are-not-cached"></span><h4>当 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 未被缓存时<a class="headerlink" href="#when-querysets-are-not-cached" title="永久链接至标题">¶</a></h4>
<p>查询结果集并不总是缓存结果。当仅计算查询结果集的 <em>部分</em> 时，会校验缓存，若没有填充缓存，则后续查询返回的项目不会被缓存。特别地说，这意味着使用数组切片或索引的 <a class="reference internal" href="#limiting-querysets"><span class="std std-ref">限制查询结果集</span></a> 不会填充缓存。</p>
<p>例如，重复的从某个查询结果集对象中取指定索引的对象会每次都查询数据库:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">queryset</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">queryset</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span> <span class="c1"># Queries the database</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">queryset</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span> <span class="c1"># Queries the database again</span>
</pre></div>
</div>
<p>不过，若全部查询结果集已被检出，就会去检查缓存:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">queryset</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">entry</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">queryset</span><span class="p">]</span> <span class="c1"># Queries the database</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">queryset</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span> <span class="c1"># Uses cache</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">queryset</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span> <span class="c1"># Uses cache</span>
</pre></div>
</div>
<p>以下展示一些例子，这些动作会触发计算全部的查询结果集，并填充缓存的过程:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">entry</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">queryset</span><span class="p">]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">bool</span><span class="p">(</span><span class="n">queryset</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">entry</span> <span class="ow">in</span> <span class="n">queryset</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">list</span><span class="p">(</span><span class="n">queryset</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">只是打印查询结果集不会填充缓存。因为调用 <code class="docutils literal notranslate"><span class="pre">__repr__()</span></code> 仅返回了完整结果集的一个切片。</p>
</div>
</div>
</div>
</div>
<div class="section" id="s-querying-jsonfield">
<span id="s-id8"></span><span id="querying-jsonfield"></span><span id="id8"></span><h2>查询 <code class="docutils literal notranslate"><span class="pre">JSONField</span></code><a class="headerlink" href="#querying-jsonfield" title="永久链接至标题">¶</a></h2>
<p><a class="reference internal" href="../../ref/models/fields.html#django.db.models.JSONField" title="django.db.models.JSONField"><code class="xref py py-class docutils literal notranslate"><span class="pre">JSONField</span></code></a> 里的查找实现是不一样的，主要因为存在key转换。为了演示，我们将使用下面这个例子：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">Dog</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">JSONField</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
</pre></div>
</div>
<div class="section" id="s-storing-and-querying-for-none">
<span id="storing-and-querying-for-none"></span><h3>保存和查询 <code class="docutils literal notranslate"><span class="pre">None</span></code> 值<a class="headerlink" href="#storing-and-querying-for-none" title="永久链接至标题">¶</a></h3>
<p>与其他字段一样，当 <code class="docutils literal notranslate"><span class="pre">None</span></code> 作为字段值来保存时，将像 SQL 的 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 值一样保存。虽然不建议这样做，但可以使用 <a class="reference internal" href="../../ref/models/expressions.html#django.db.models.Value" title="django.db.models.Value"><code class="xref py py-class docutils literal notranslate"><span class="pre">Value('null')</span></code></a> 来存储 JSON 的 <code class="docutils literal notranslate"><span class="pre">null</span></code> 值。</p>
<p>无论存储哪个值，当从数据库中检索时，Python表示JSON的空值和 SQL 里的 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 一样，都是 <code class="docutils literal notranslate"><span class="pre">None</span></code> 。因此，很难区分它们。</p>
<p>这只适用于 <code class="docutils literal notranslate"><span class="pre">None</span></code> 值作为字段的顶级值。如果 <code class="docutils literal notranslate"><span class="pre">None</span></code> 被保存在列表或字典中，它将始终被解释为JSON的 <code class="docutils literal notranslate"><span class="pre">null</span></code> 值。</p>
<p>当查询时，<code class="docutils literal notranslate"><span class="pre">None</span></code> 值将一直被解释为JSON的``null``。要查询SQL的``NULL``，请使用 <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-isnull"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">isnull</span></code></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Max&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>  <span class="c1"># SQL NULL.</span>
<span class="go">&lt;Dog: Max&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Archie&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">Value</span><span class="p">(</span><span class="s1">&#39;null&#39;</span><span class="p">))</span>  <span class="c1"># JSON null.</span>
<span class="go">&lt;Dog: Archie&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Archie&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">Value</span><span class="p">(</span><span class="s1">&#39;null&#39;</span><span class="p">))</span>
<span class="go">&lt;QuerySet [&lt;Dog: Archie&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__isnull</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Max&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__isnull</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Archie&gt;]&gt;</span>
</pre></div>
</div>
<p>除非你确定要使用SQL 的 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 值，否则请考虑设置 <code class="docutils literal notranslate"><span class="pre">null=False</span></code> 并为空值提供合适的默认值，例如 <code class="docutils literal notranslate"><span class="pre">default=dict</span></code> 。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">保存JSON的 <code class="docutils literal notranslate"><span class="pre">null</span></code> 值不违反Django的 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.Field.null" title="django.db.models.Field.null"><code class="xref py py-attr docutils literal notranslate"><span class="pre">null=False</span></code></a> 。</p>
</div>
</div>
<div class="section" id="s-key-index-and-path-transforms">
<span id="s-std:fieldlookup-jsonfield.key"></span><span id="key-index-and-path-transforms"></span><span id="std:fieldlookup-jsonfield.key"></span><h3>Key, index, 和路径转换<a class="headerlink" href="#key-index-and-path-transforms" title="永久链接至标题">¶</a></h3>
<p>为了查询给定的字典键，请将该键作为查询名：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Rufus&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span>
<span class="gp">... </span>    <span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;labrador&#39;</span><span class="p">,</span>
<span class="gp">... </span>    <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="gp">... </span>        <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="s1">&#39;other_pets&#39;</span><span class="p">:</span> <span class="p">[{</span>
<span class="gp">... </span>            <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Fishy&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="p">}],</span>
<span class="gp">... </span>    <span class="p">},</span>
<span class="gp">... </span><span class="p">})</span>
<span class="go">&lt;Dog: Rufus&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Meg&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">})</span>
<span class="go">&lt;Dog: Meg&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__breed</span><span class="o">=</span><span class="s1">&#39;collie&#39;</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Meg&gt;]&gt;</span>
</pre></div>
</div>
<p>可以将多个键链接起来形成一个路径查询：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__owner__name</span><span class="o">=</span><span class="s1">&#39;Bob&#39;</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Rufus&gt;]&gt;</span>
</pre></div>
</div>
<p>如果键是个整型，那么它将在数组中被解释成一个索引：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__owner__other_pets__0__name</span><span class="o">=</span><span class="s1">&#39;Fishy&#39;</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Rufus&gt;]&gt;</span>
</pre></div>
</div>
<p>如果要查询的键与另一个查询的键名冲突，请改用 <a class="reference internal" href="#std:fieldlookup-jsonfield.contains"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">contains</span></code></a> 来查询。</p>
<p>如果查询时缺少键名，请使用 <code class="docutils literal notranslate"><span class="pre">isnull</span></code> 查询：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Shep&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Shep&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__owner__isnull</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Shep&gt;]&gt;</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">上面给出的例子隐式地使用了 <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-exact"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">exact</span></code></a> 查找。Key，索引和路径转换也可以用：<a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-icontains"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">icontains</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-endswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">endswith</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-iendswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">iendswith</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-iexact"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">iexact</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-regex"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">regex</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-iregex"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">iregex</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-startswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">startswith</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-istartswith"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">istartswith</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-lt"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">lt</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-lte"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">lte</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-gt"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">gt</span></code></a>, <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-gte"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">gte</span></code></a>, 以及:ref:<cite>containment-and-key-lookups</cite> 。</p>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">由于键路径查询的工作方式，<code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code> 和 <code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code> 不能保证产生详尽的集合。如果你想包含没有路径的对象，请添加 <code class="docutils literal notranslate"><span class="pre">isnull</span></code> 查找。</p>
</div>
<div class="admonition warning">
<p class="first admonition-title">警告</p>
<p class="last">因为任何字符串在JSON对象中都可以作为key，因此除了下面列出的这些查找会被解释为键查找。不会引发任何错误。要特别小心输入错误，并且要检查查询是否正常工作。</p>
</div>
<div class="admonition-mariadb-and-oracle-users admonition">
<p class="first admonition-title">MariaDB 和 Oracle 用户</p>
<p class="last">对Key, 索引, 或者路径转换使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.order_by" title="django.db.models.query.QuerySet.order_by"><code class="xref py py-meth docutils literal notranslate"><span class="pre">order_by()</span></code></a> 会使用值的字符串表示来进行对象排序。这是因为MariaDB 和 Oracle 数据库不支持将JSON值转换成它们的等效SQL值的函数。</p>
</div>
<div class="admonition-oracle-users admonition">
<p class="first admonition-title">Oracle 用户</p>
<p class="last">在Oracle数据库上，在 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.exclude" title="django.db.models.query.QuerySet.exclude"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code></a> 查询里使用 <code class="docutils literal notranslate"><span class="pre">None</span></code> 作为查找值将返回给定路径上没有 <code class="docutils literal notranslate"><span class="pre">null</span></code> 值的对象。在其他数据库后端，查询将返回具有路径和不为 <code class="docutils literal notranslate"><span class="pre">null</span></code> 值的对象。</p>
</div>
<div class="admonition-postgresql-users admonition">
<p class="first admonition-title">PostgreSQL 用户</p>
<p class="last">在 PostgreSQL 上，如果只使用一个key或索引，那么会使用 SQL 运算符 <code class="docutils literal notranslate"><span class="pre">-&gt;</span></code> 。如果使用多个操作符，那么会使用 <code class="docutils literal notranslate"><span class="pre">#&gt;</span></code> 运算符。</p>
</div>
</div>
<div class="section" id="s-containment-and-key-lookups">
<span id="s-id9"></span><span id="containment-and-key-lookups"></span><span id="id9"></span><h3>包含与键查找<a class="headerlink" href="#containment-and-key-lookups" title="永久链接至标题">¶</a></h3>
<div class="section" id="s-contains">
<span id="s-std:fieldlookup-jsonfield.contains"></span><span id="contains"></span><span id="std:fieldlookup-jsonfield.contains"></span><h4><code class="docutils literal notranslate"><span class="pre">contains</span></code><a class="headerlink" href="#contains" title="永久链接至标题">¶</a></h4>
<p><code class="docutils literal notranslate"><span class="pre">JSONField</span></code> 上的 <a class="reference internal" href="../../ref/models/querysets.html#std:fieldlookup-contains"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">contains</span></code></a> 查找已被覆盖。返回的对象是那些给定的键值对都包含在顶级字段中的对象。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Rufus&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;labrador&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Rufus&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Meg&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Meg&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Fred&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{})</span>
<span class="go">&lt;Dog: Fred&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__contains</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;QuerySet [&lt;Dog: Rufus&gt;, &lt;Dog: Meg&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__contains</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">})</span>
<span class="go">&lt;QuerySet [&lt;Dog: Meg&gt;]&gt;</span>
</pre></div>
</div>
<div class="admonition-oracle-and-sqlite admonition">
<p class="first admonition-title">Oracle 和 SQLite</p>
<p class="last">Oracle 和 SQLite 不支持 <code class="docutils literal notranslate"><span class="pre">contains</span></code> 。</p>
</div>
</div>
<div class="section" id="s-contained-by">
<span id="s-std:fieldlookup-jsonfield.contained_by"></span><span id="contained-by"></span><span id="std:fieldlookup-jsonfield.contained_by"></span><h4><code class="docutils literal notranslate"><span class="pre">contained_by</span></code><a class="headerlink" href="#contained-by" title="永久链接至标题">¶</a></h4>
<p>这是 <a class="reference internal" href="#std:fieldlookup-jsonfield.contains"><code class="xref std std-lookup docutils literal notranslate"><span class="pre">contains</span></code></a> 查找逆过程——返回的对象将是那些传递的值中的子集在对象上的键值对。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Rufus&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;labrador&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Rufus&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Meg&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Meg&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Fred&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{})</span>
<span class="go">&lt;Dog: Fred&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__contained_by</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;QuerySet [&lt;Dog: Meg&gt;, &lt;Dog: Fred&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__contained_by</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">})</span>
<span class="go">&lt;QuerySet [&lt;Dog: Fred&gt;]&gt;</span>
</pre></div>
</div>
<div class="admonition-oracle-and-sqlite admonition">
<p class="first admonition-title">Oracle 和 SQLite</p>
<p class="last">Oracle 和 SQLite 不支持 <code class="docutils literal notranslate"><span class="pre">contained_by</span></code> 。</p>
</div>
</div>
<div class="section" id="s-has-key">
<span id="s-std:fieldlookup-jsonfield.has_key"></span><span id="has-key"></span><span id="std:fieldlookup-jsonfield.has_key"></span><h4><code class="docutils literal notranslate"><span class="pre">has_key</span></code><a class="headerlink" href="#has-key" title="永久链接至标题">¶</a></h4>
<p>返回给定的键位于数据顶层的对象。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Rufus&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;labrador&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Rufus&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Meg&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Meg&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__has_key</span><span class="o">=</span><span class="s1">&#39;owner&#39;</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Dog: Meg&gt;]&gt;</span>
</pre></div>
</div>
</div>
<div class="section" id="s-has-keys">
<span id="s-std:fieldlookup-jsonfield.has_any_keys"></span><span id="has-keys"></span><span id="std:fieldlookup-jsonfield.has_any_keys"></span><h4><code class="docutils literal notranslate"><span class="pre">has_keys</span></code><a class="headerlink" href="#has-keys" title="永久链接至标题">¶</a></h4>
<p>返回所有给定的键位于数据顶层的对象。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Rufus&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;labrador&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Rufus&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Meg&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;collie&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Meg&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__has_keys</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;breed&#39;</span><span class="p">,</span> <span class="s1">&#39;owner&#39;</span><span class="p">])</span>
<span class="go">&lt;QuerySet [&lt;Dog: Meg&gt;]&gt;</span>
</pre></div>
</div>
</div>
<div class="section" id="s-has-any-keys">
<span id="s-std:fieldlookup-jsonfield.has_keys"></span><span id="has-any-keys"></span><span id="std:fieldlookup-jsonfield.has_keys"></span><h4><code class="docutils literal notranslate"><span class="pre">has_any_keys</span></code><a class="headerlink" href="#has-any-keys" title="永久链接至标题">¶</a></h4>
<p>返回任何给定的键位于数据顶层的对象。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Rufus&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;breed&#39;</span><span class="p">:</span> <span class="s1">&#39;labrador&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Rufus&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Meg&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="s1">&#39;Bob&#39;</span><span class="p">})</span>
<span class="go">&lt;Dog: Meg&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Dog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">data__has_any_keys</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;owner&#39;</span><span class="p">,</span> <span class="s1">&#39;breed&#39;</span><span class="p">])</span>
<span class="go">&lt;QuerySet [&lt;Dog: Rufus&gt;, &lt;Dog: Meg&gt;]&gt;</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="s-complex-lookups-with-q-objects">
<span id="s-complex-lookups-with-q"></span><span id="complex-lookups-with-q-objects"></span><span id="complex-lookups-with-q"></span><h2>通过 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象完成复杂查询<a class="headerlink" href="#complex-lookups-with-q-objects" title="永久链接至标题">¶</a></h2>
<p>在类似 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a> 中，查询使用的关键字参数是通过 &quot;AND&quot; 连接起来的。如果你要执行更复杂的查询（例如，由 <code class="docutils literal notranslate"><span class="pre">OR</span></code> 语句连接的查询），你可以使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.Q" title="django.db.models.Q"><code class="xref py py-class docutils literal notranslate"><span class="pre">Q</span> <span class="pre">对象</span></code></a>。</p>
<p>一个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.Q" title="django.db.models.Q"><code class="xref py py-class docutils literal notranslate"><span class="pre">Q</span> <span class="pre">对象</span></code></a> (<code class="docutils literal notranslate"><span class="pre">django.db.models.Q</span></code>) 用于压缩关键字参数集合。这些关键字参数由前文 &quot;Field lookups&quot; 指定。</p>
<p>例如，该 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象压缩了一个 <code class="docutils literal notranslate"><span class="pre">LIKE</span></code> 查询:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
<span class="n">Q</span><span class="p">(</span><span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;What&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象能通过 <code class="docutils literal notranslate"><span class="pre">&amp;</span></code> 和 <code class="docutils literal notranslate"><span class="pre">|</span></code> 操作符连接起来。当操作符被用于两个 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象之间时会生成一个新的 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象。</p>
<p>例如，该语句生成一个 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象，表示两个 <code class="docutils literal notranslate"><span class="pre">&quot;question_startswith&quot;</span></code> 查询语句之间的 &quot;OR&quot; 关系:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Q</span><span class="p">(</span><span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;Who&#39;</span><span class="p">)</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;What&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这等价于以下 SQL <code class="docutils literal notranslate"><span class="pre">WHERE</span></code> 字句:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">WHERE</span> <span class="n">question</span> <span class="n">LIKE</span> <span class="s1">&#39;Who%&#39;</span> <span class="n">OR</span> <span class="n">question</span> <span class="n">LIKE</span> <span class="s1">&#39;What%&#39;</span>
</pre></div>
</div>
<p>你能通过 <code class="docutils literal notranslate"><span class="pre">&amp;</span></code> 和 <code class="docutils literal notranslate"><span class="pre">|</span></code> 操作符和括号分组，组合任意复杂度的语句。当然， <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象也可通过 <code class="docutils literal notranslate"><span class="pre">~</span></code> 操作符反转，允许在组合查询中组合普通查询或反向 (<code class="docutils literal notranslate"><span class="pre">NOT</span></code>) 查询:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Q</span><span class="p">(</span><span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;Who&#39;</span><span class="p">)</span> <span class="o">|</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="mi">2005</span><span class="p">)</span>
</pre></div>
</div>
<p>每个接受关键字参数的查询函数 (例如 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.filter" title="django.db.models.query.QuerySet.filter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">filter()</span></code></a>， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.exclude" title="django.db.models.query.QuerySet.exclude"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exclude()</span></code></a>， <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.get" title="django.db.models.query.QuerySet.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a>) 也同时接受一个或多个 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象作为位置（未命名的）参数。若你为查询函数提供了多个 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象参数，这些参数会通过 &quot;AND&quot; 连接。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Poll</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
    <span class="n">Q</span><span class="p">(</span><span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;Who&#39;</span><span class="p">),</span>
    <span class="n">Q</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
<span class="p">)</span>
</pre></div>
</div>
<p>...粗略地转为 SQL：</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">SELECT</span> <span class="o">*</span> <span class="k">from</span> <span class="n">polls</span> <span class="k">WHERE</span> <span class="n">question</span> <span class="k">LIKE</span> <span class="s1">&#39;Who%&#39;</span>
    <span class="k">AND</span> <span class="p">(</span><span class="n">pub_date</span> <span class="o">=</span> <span class="s1">&#39;2005-05-02&#39;</span> <span class="k">OR</span> <span class="n">pub_date</span> <span class="o">=</span> <span class="s1">&#39;2005-05-06&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>查询函数能混合使用 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象和关键字参数。所有提供给查询函数的参数（即关键字参数或 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象）均通过 &quot;AND&quot; 连接。然而，若提供了 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象，那么它必须位于所有关键字参数之前。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Poll</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
    <span class="n">Q</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">)),</span>
    <span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;Who&#39;</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>……会是一个有效的查询，等效于前文的例子；但是:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># INVALID QUERY</span>
<span class="n">Poll</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
    <span class="n">question__startswith</span><span class="o">=</span><span class="s1">&#39;Who&#39;</span><span class="p">,</span>
    <span class="n">Q</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">date</span><span class="p">(</span><span class="mi">2005</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
<span class="p">)</span>
</pre></div>
</div>
<p>……却是无效的。</p>
<div class="admonition seealso">
<p class="first admonition-title">参见</p>
<p class="last">Django 单元测试中的 <a class="reference external" href="https://github.com/django/django/blob/main/tests/or_lookups/tests.py">OR 查询实例</a> 展示了 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 的用法。</p>
</div>
</div>
<div class="section" id="s-comparing-objects">
<span id="comparing-objects"></span><h2>比较对象<a class="headerlink" href="#comparing-objects" title="永久链接至标题">¶</a></h2>
<p>要比较两个模型实例，使用标准的 Python 比较操作符，两个等号： <code class="docutils literal notranslate"><span class="pre">==</span></code>。实际上，这比较了两个模型实例的主键值。</p>
<p>使用前文的 <code class="docutils literal notranslate"><span class="pre">Entry</span></code>，以下的两个语句是等效的:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">some_entry</span> <span class="o">==</span> <span class="n">other_entry</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">some_entry</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">other_entry</span><span class="o">.</span><span class="n">id</span>
</pre></div>
</div>
<p>若模型主键名不是 <code class="docutils literal notranslate"><span class="pre">id</span></code>，没问题。比较时总会使用主键，不管它叫啥。例如，若模型的主键字段名为 <code class="docutils literal notranslate"><span class="pre">name</span></code>，以下两个语句是等效的:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">some_obj</span> <span class="o">==</span> <span class="n">other_obj</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">some_obj</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">other_obj</span><span class="o">.</span><span class="n">name</span>
</pre></div>
</div>
</div>
<div class="section" id="s-deleting-objects">
<span id="s-topics-db-queries-delete"></span><span id="deleting-objects"></span><span id="topics-db-queries-delete"></span><h2>删除对象<a class="headerlink" href="#deleting-objects" title="永久链接至标题">¶</a></h2>
<p>通常，删除方法被命名为 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.delete" title="django.db.models.Model.delete"><code class="xref py py-meth docutils literal notranslate"><span class="pre">delete()</span></code></a>。该方法立刻删除对象，并返回被删除的对象数量和一个包含了每个被删除对象类型的数量的字典。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">e</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="go">(1, {&#39;weblog.Entry&#39;: 1})</span>
</pre></div>
</div>
<p>你也能批量删除对象。所有 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 都有个 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.delete" title="django.db.models.query.QuerySet.delete"><code class="xref py py-meth docutils literal notranslate"><span class="pre">delete()</span></code></a> 方法，它会删除 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 中的所有成员。</p>
<p>例如，这会删除 2005 发布的所有 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 对象:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="mi">2005</span><span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="go">(5, {&#39;webapp.Entry&#39;: 5})</span>
</pre></div>
</div>
<p>请记住，只要有机会的话，这会通过纯 SQL 语句执行，所以就无需在过程中调用每个对象的删除方法了。若你为模型类提供了自定义的 <code class="docutils literal notranslate"><span class="pre">delete()</span></code> 方法，且希望确保调用了该方法，你需要 “手动” 删除该模型的实例（例如，如，遍历 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>，在每个对象上分别调用 <code class="docutils literal notranslate"><span class="pre">delete()</span></code> 方法），而不是使用 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的批量删除方法 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.delete" title="django.db.models.query.QuerySet.delete"><code class="xref py py-meth docutils literal notranslate"><span class="pre">delete()</span></code></a>。</p>
<p>当 Django 删除某个对象时，默认会模仿 SQL 约束 <code class="docutils literal notranslate"><span class="pre">ON</span> <span class="pre">DELETE</span> <span class="pre">CASCADE</span></code> 的行为——换而言之，某个对象被删除时，关联对象也会被删除。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="c1"># This will delete the Blog and all of its Entry objects.</span>
<span class="n">b</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
<p>这种约束行为由 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 的 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey.on_delete" title="django.db.models.ForeignKey.on_delete"><code class="xref py py-attr docutils literal notranslate"><span class="pre">on_delete</span></code></a> 参数指定。</p>
<p>注意 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.delete" title="django.db.models.query.QuerySet.delete"><code class="xref py py-meth docutils literal notranslate"><span class="pre">delete()</span></code></a> 是唯一未在 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 上暴漏的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 方法。这是一种安全机制，避免你不小心调用了 <code class="docutils literal notranslate"><span class="pre">Entry.objects.delete()</span></code>，删除了 <em>所有的</em> 条目。若你 <em>确实</em> 想要删除所有对象，你必须显示请求完整结果集合:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="s-copying-model-instances">
<span id="s-topics-db-queries-copy"></span><span id="copying-model-instances"></span><span id="topics-db-queries-copy"></span><h2>复制模型实例<a class="headerlink" href="#copying-model-instances" title="永久链接至标题">¶</a></h2>
<p>Although there is no built-in method for copying model instances, it is
possible to easily create new instance with all fields' values copied. In the
simplest case, you can set <code class="docutils literal notranslate"><span class="pre">pk</span></code> to <code class="docutils literal notranslate"><span class="pre">None</span></code> and
<a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model._state" title="django.db.models.Model._state"><code class="xref py py-attr docutils literal notranslate"><span class="pre">_state.adding</span></code></a> to <code class="docutils literal notranslate"><span class="pre">True</span></code>. Using our
blog example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">blog</span> <span class="o">=</span> <span class="n">Blog</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;My blog&#39;</span><span class="p">,</span> <span class="n">tagline</span><span class="o">=</span><span class="s1">&#39;Blogging is easy&#39;</span><span class="p">)</span>
<span class="n">blog</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># blog.pk == 1</span>

<span class="n">blog</span><span class="o">.</span><span class="n">pk</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">blog</span><span class="o">.</span><span class="n">_state</span><span class="o">.</span><span class="n">adding</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">blog</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># blog.pk == 2</span>
</pre></div>
</div>
<p>若你使用了集成，事情会更复杂。考虑下 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 的一个子类:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ThemeBlog</span><span class="p">(</span><span class="n">Blog</span><span class="p">):</span>
    <span class="n">theme</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>

<span class="n">django_blog</span> <span class="o">=</span> <span class="n">ThemeBlog</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Django&#39;</span><span class="p">,</span> <span class="n">tagline</span><span class="o">=</span><span class="s1">&#39;Django is easy&#39;</span><span class="p">,</span> <span class="n">theme</span><span class="o">=</span><span class="s1">&#39;python&#39;</span><span class="p">)</span>
<span class="n">django_blog</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># django_blog.pk == 3</span>
</pre></div>
</div>
<p>Due to how inheritance works, you have to set both <code class="docutils literal notranslate"><span class="pre">pk</span></code> and <code class="docutils literal notranslate"><span class="pre">id</span></code> to
<code class="docutils literal notranslate"><span class="pre">None</span></code>, and <code class="docutils literal notranslate"><span class="pre">_state.adding</span></code> to <code class="docutils literal notranslate"><span class="pre">True</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">django_blog</span><span class="o">.</span><span class="n">pk</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">django_blog</span><span class="o">.</span><span class="n">id</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">django_blog</span><span class="o">.</span><span class="n">_state</span><span class="o">.</span><span class="n">adding</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">django_blog</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># django_blog.pk == 4</span>
</pre></div>
</div>
<p>该方法不会拷贝不是模型数据表中的关联关系。例如， <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 有一个对 <code class="docutils literal notranslate"><span class="pre">Author</span></code> 的 <code class="docutils literal notranslate"><span class="pre">ManyToManyField</span></code> 关联关系。在复制条目后，你必须为新条目设置多对多关联关系。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">entry</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># some previous entry</span>
<span class="n">old_authors</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="n">entry</span><span class="o">.</span><span class="n">pk</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">entry</span><span class="o">.</span><span class="n">_state</span><span class="o">.</span><span class="n">adding</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">entry</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="n">entry</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">old_authors</span><span class="p">)</span>
</pre></div>
</div>
<p>对于 <code class="docutils literal notranslate"><span class="pre">OneToOneField</span></code> 关联，你必须拷贝关联对象，并将其指定给新对象的关联字段，避免违反一对一唯一性约束。例如，指定前文复制的 <code class="docutils literal notranslate"><span class="pre">entry</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">detail</span> <span class="o">=</span> <span class="n">EntryDetail</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">detail</span><span class="o">.</span><span class="n">pk</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">detail</span><span class="o">.</span><span class="n">_state</span><span class="o">.</span><span class="n">adding</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">detail</span><span class="o">.</span><span class="n">entry</span> <span class="o">=</span> <span class="n">entry</span>
<span class="n">detail</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="s-updating-multiple-objects-at-once">
<span id="s-topics-db-queries-update"></span><span id="updating-multiple-objects-at-once"></span><span id="topics-db-queries-update"></span><h2>一次修改多个对象<a class="headerlink" href="#updating-multiple-objects-at-once" title="永久链接至标题">¶</a></h2>
<p>有时候，你想统一设置 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 中的所有对象的某个字段。你可以通过 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.update" title="django.db.models.query.QuerySet.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a> 达到目的。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Update all the headlines with pub_date in 2007.</span>
<span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="mi">2007</span><span class="p">)</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">headline</span><span class="o">=</span><span class="s1">&#39;Everything is the same&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>你仅能用此方法设置非关联字段和 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 字段。要修改非关联字段，需要用常量提供新值。要修改 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 字段，将新值置为目标模型的新实例。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>

<span class="go"># Change every Entry so that it belongs to this Blog.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">blog</span><span class="o">=</span><span class="n">b</span><span class="p">)</span>
</pre></div>
</div>
<p>方法 <code class="docutils literal notranslate"><span class="pre">update()</span></code> 立刻被运行，并返回匹配查询调节的行数（若某些行早已是新值，则可能不等于实际匹配的行数）。更新 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 的唯一限制即它只能操作一个数据表：该模型的主表。你可以基于关联字段进行筛选，但你只能更新模型主表中的列。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>

<span class="go"># Update all the headlines belonging to this Blog.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog</span><span class="o">=</span><span class="n">b</span><span class="p">)</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">headline</span><span class="o">=</span><span class="s1">&#39;Everything is the same&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>要认识到 <code class="docutils literal notranslate"><span class="pre">update()</span></code> 方法是直接转为 SQL 语句的。这是一种用于直接更新的批量操作。它并不会调用模型的 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 方法，或发射 <code class="docutils literal notranslate"><span class="pre">pre_save</span></code> 或 <code class="docutils literal notranslate"><span class="pre">post_save</span></code> 信号（调用 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 会触发信号），或使用 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.DateField.auto_now" title="django.db.models.DateField.auto_now"><code class="xref py py-attr docutils literal notranslate"><span class="pre">auto_now</span></code></a> 字段选项。若想保存 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 中的每项，并确保调用了每个实例的 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 方法，你并不需要任何特殊的函数来处理此问题。迭代它们，并调用它们的 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 方法:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">my_queryset</span><span class="p">:</span>
    <span class="n">item</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>调用更新方法时也能使用 <a class="reference internal" href="../../ref/models/expressions.html#django.db.models.F" title="django.db.models.F"><code class="xref py py-class docutils literal notranslate"><span class="pre">F</span> <span class="pre">表达式</span></code></a> 基于同一模型另一个字段的值更新某个字段。这在基于计数器的当前值增加其值时特别有用。例如，要增加针对博客中每项条目的 pingback 技术:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">number_of_pingbacks</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;number_of_pingbacks&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>然而，与过滤器中的 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象和排除字句不同，你不能在更新方法中使用 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象的同时使用 join——你只能引用被更新模型的内部字段。若你试着在使用 join 字句时使用 <code class="docutils literal notranslate"><span class="pre">F()</span></code> 对象，会抛出一个 <code class="docutils literal notranslate"><span class="pre">FieldError()</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This will raise a FieldError</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">headline</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">&#39;blog__name&#39;</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="section" id="s-related-objects">
<span id="s-topics-db-queries-related"></span><span id="related-objects"></span><span id="topics-db-queries-related"></span><h2>关联对象<a class="headerlink" href="#related-objects" title="永久链接至标题">¶</a></h2>
<p>当你在模型中定义了关联关系（如 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a>， <a class="reference internal" href="../../ref/models/fields.html#django.db.models.OneToOneField" title="django.db.models.OneToOneField"><code class="xref py py-class docutils literal notranslate"><span class="pre">OneToOneField</span></code></a>， 或 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a>），该模型的实例将会自动获取一套 API，能快捷地访问关联对象。</p>
<p>拿本文开始的模型做例子，一个 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 对象 <code class="docutils literal notranslate"><span class="pre">e</span></code> 通过 <code class="docutils literal notranslate"><span class="pre">blog</span></code> 属性获取其关联的 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 对象： <code class="docutils literal notranslate"><span class="pre">e.blog</span></code>。</p>
<p>（在幕后，这个函数是由  Python <a class="reference external" href="https://docs.python.org/3/howto/descriptor.html" title="(在 Python v3.10)"><span class="xref std std-doc">descriptors</span></a> 实现的。这玩意一般不会麻烦你，但是我们为你指出了注意点。）</p>
<p>Django 也提供了从关联关系 <em>另一边</em> 访问的 API —— 从被关联模型到定义关联关系的模型的连接。例如，一个 <code class="docutils literal notranslate"><span class="pre">Blog</span></code> 对象 <code class="docutils literal notranslate"><span class="pre">b</span></code> 能通过 <code class="docutils literal notranslate"><span class="pre">entry_set</span></code> 属性 <code class="docutils literal notranslate"><span class="pre">b.entry_set.all()</span></code> 访问包含所有关联 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 对象的列表。</p>
<p>本章节中的所有例子都是用了本页开头定义的 <code class="docutils literal notranslate"><span class="pre">Blog</span></code>， <code class="docutils literal notranslate"><span class="pre">Author</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 模型。</p>
<div class="section" id="s-one-to-many-relationships">
<span id="one-to-many-relationships"></span><h3>一对多关联<a class="headerlink" href="#one-to-many-relationships" title="永久链接至标题">¶</a></h3>
<div class="section" id="s-forward">
<span id="forward"></span><h4>正向访问<a class="headerlink" href="#forward" title="永久链接至标题">¶</a></h4>
<p>若模型有个 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a>，该模型的实例能通过其属性访问关联（外部的）对象。</p>
<p>举例：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">e</span><span class="o">.</span><span class="n">blog</span> <span class="c1"># Returns the related Blog object.</span>
</pre></div>
</div>
<p>你可以通过 foreign-key 属性获取和设置值。如你所想，对外键的修改直到你调用 <a class="reference internal" href="../../ref/models/instances.html#django.db.models.Model.save" title="django.db.models.Model.save"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> 后才会被存入数据库。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">e</span><span class="o">.</span><span class="n">blog</span> <span class="o">=</span> <span class="n">some_blog</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">e</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>若 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 字段配置了 <code class="docutils literal notranslate"><span class="pre">null=True</span></code> （即其允许 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 值），你可以指定值为 <code class="docutils literal notranslate"><span class="pre">None</span></code> 移除关联。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">e</span><span class="o">.</span><span class="n">blog</span> <span class="o">=</span> <span class="kc">None</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">e</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># &quot;UPDATE blog_entry SET blog_id = NULL ...;&quot;</span>
</pre></div>
</div>
<p>首次通过正向一对多关联访问关联对象时会缓存关联关系。后续在同一对象上通过外键的访问也会被缓存。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">blog</span><span class="p">)</span>  <span class="c1"># Hits the database to retrieve the associated Blog.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">blog</span><span class="p">)</span>  <span class="c1"># Doesn&#39;t hit the database; uses cached version.</span>
</pre></div>
</div>
<p>注意 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet.select_related" title="django.db.models.query.QuerySet.select_related"><code class="xref py py-meth docutils literal notranslate"><span class="pre">select_related()</span></code></a>  <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 方法会预先用所有一对多关联对象填充缓存。例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">select_related</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">blog</span><span class="p">)</span>  <span class="c1"># Doesn&#39;t hit the database; uses cached version.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">blog</span><span class="p">)</span>  <span class="c1"># Doesn&#39;t hit the database; uses cached version.</span>
</pre></div>
</div>
</div>
<div class="section" id="s-following-relationships-backward">
<span id="s-backwards-related-objects"></span><span id="following-relationships-backward"></span><span id="backwards-related-objects"></span><h4>“反向” 关联<a class="headerlink" href="#following-relationships-backward" title="永久链接至标题">¶</a></h4>
<p>若模型有 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a>，外键关联的模型实例将能访问 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a>，后者会返回第一个模型的所有实例。默认情况下，该 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 名为 <code class="docutils literal notranslate"><span class="pre">FOO_set</span></code>， <code class="docutils literal notranslate"><span class="pre">FOO</span></code> 即源模型名的小写形式。 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 返回 <code class="docutils literal notranslate"><span class="pre">QuerySets</span></code>，后者能以 “检索对象” 章节介绍的方式进行筛选和操作。</p>
<p>举例：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># Returns all Entry objects related to Blog.</span>

<span class="go"># b.entry_set is a Manager that returns QuerySets.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
</pre></div>
</div>
<p>你可以在定义 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 时设置 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey.related_name" title="django.db.models.ForeignKey.related_name"><code class="xref py py-attr docutils literal notranslate"><span class="pre">related_name</span></code></a> 参数重写这个 <code class="docutils literal notranslate"><span class="pre">FOO_set</span></code> 名。例如，若修改 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 模型为 <code class="docutils literal notranslate"><span class="pre">blog</span> <span class="pre">=</span> <span class="pre">ForeignKey(Blog,</span> <span class="pre">on_delete=models.CASCADE,</span> <span class="pre">related_name='entries')</span></code>，前文示例代码会看起来像这样:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">entries</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># Returns all Entry objects related to Blog.</span>

<span class="go"># b.entries is a Manager that returns QuerySets.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">entries</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">headline__contains</span><span class="o">=</span><span class="s1">&#39;Lennon&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span><span class="o">.</span><span class="n">entries</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="s-using-a-custom-reverse-manager">
<span id="s-using-custom-reverse-manager"></span><span id="using-a-custom-reverse-manager"></span><span id="using-custom-reverse-manager"></span><h4>使用自定义反向管理器<a class="headerlink" href="#using-a-custom-reverse-manager" title="永久链接至标题">¶</a></h4>
<p><a class="reference internal" href="../../ref/models/relations.html#django.db.models.fields.related.RelatedManager" title="django.db.models.fields.related.RelatedManager"><code class="xref py py-class docutils literal notranslate"><span class="pre">RelatedManager</span></code></a> 反向关联的默认实现是该模型 <a class="reference internal" href="managers.html#manager-names"><span class="std std-ref">默认管理器</span></a> 一个实例。若你想为某个查询指定一个不同的管理器，可以使用如下语法:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="c1">#...</span>
    <span class="n">objects</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Manager</span><span class="p">()</span>  <span class="c1"># Default Manager</span>
    <span class="n">entries</span> <span class="o">=</span> <span class="n">EntryManager</span><span class="p">()</span>    <span class="c1"># Custom Manager</span>

<span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">b</span><span class="o">.</span><span class="n">entry_set</span><span class="p">(</span><span class="n">manager</span><span class="o">=</span><span class="s1">&#39;entries&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>若 <code class="docutils literal notranslate"><span class="pre">EntryManager</span></code> 在其 <code class="docutils literal notranslate"><span class="pre">get_queryset()</span></code> 方法执行了默认过滤行为，改行为会应用到 <code class="docutils literal notranslate"><span class="pre">all()</span></code> 调用中。</p>
<p>指定一个自定义反向管理也允许你调用模型自定义方法:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span><span class="o">.</span><span class="n">entry_set</span><span class="p">(</span><span class="n">manager</span><span class="o">=</span><span class="s1">&#39;entries&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">is_published</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="s-additional-methods-to-handle-related-objects">
<span id="additional-methods-to-handle-related-objects"></span><h4>管理关联对象的额外方法<a class="headerlink" href="#additional-methods-to-handle-related-objects" title="永久链接至标题">¶</a></h4>
<p><a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 还有方法能处理关联对象集合。除了上面的 “检索对象” 中定义的 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> 方法以外，以下是每项的简要介绍，而完整的细节能在 <a class="reference internal" href="../../ref/models/relations.html"><span class="doc">关联对象参考</span></a> 中找到。</p>
<dl class="docutils">
<dt><code class="docutils literal notranslate"><span class="pre">add(obj1,</span> <span class="pre">obj2,</span> <span class="pre">...)</span></code></dt>
<dd>将特定的模型对象加入关联对象集合。</dd>
<dt><code class="docutils literal notranslate"><span class="pre">create(**kwargs)</span></code></dt>
<dd>创建一个新对象，保存，并将其放入关联对象集合中。返回新创建的对象。</dd>
<dt><code class="docutils literal notranslate"><span class="pre">remove(obj1,</span> <span class="pre">obj2,</span> <span class="pre">...)</span></code></dt>
<dd>从关联对象集合删除指定模型对象。</dd>
<dt><code class="docutils literal notranslate"><span class="pre">clear()</span></code></dt>
<dd>从关联对象集合删除所有对象。</dd>
<dt><code class="docutils literal notranslate"><span class="pre">set(objs)</span></code></dt>
<dd>替换关联对象集合</dd>
</dl>
<p>要指定关联集合的成员，调用 <code class="docutils literal notranslate"><span class="pre">set()</span></code> 方法，并传入可迭代的对象实例集合。例如，若 <code class="docutils literal notranslate"><span class="pre">e1</span></code> 和 <code class="docutils literal notranslate"><span class="pre">e2</span></code> 都是 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 实例:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="o">=</span> <span class="n">Blog</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">b</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">set</span><span class="p">([</span><span class="n">e1</span><span class="p">,</span> <span class="n">e2</span><span class="p">])</span>
</pre></div>
</div>
<p>若能使用 <code class="docutils literal notranslate"><span class="pre">clear()</span></code> 方法， <code class="docutils literal notranslate"><span class="pre">entry_set</span></code> 中所有旧对象会在将可迭代集合（本例中是个列表）中的对象加入其中之前被删除。若 <em>不能</em> 使用 <code class="docutils literal notranslate"><span class="pre">clear()</span></code> 方法，添加新对象时不会删除旧对象。</p>
<p>本节介绍的所有 “反向” 操作对数据库都是立刻生效的。每次的增加，创建和删除都是及时自动地保存至数据库。</p>
</div>
</div>
<div class="section" id="s-many-to-many-relationships">
<span id="s-m2m-reverse-relationships"></span><span id="many-to-many-relationships"></span><span id="m2m-reverse-relationships"></span><h3>多对多关联<a class="headerlink" href="#many-to-many-relationships" title="永久链接至标题">¶</a></h3>
<p>多对多关联的两端均自动获取访问另一端的 API。该 API 的工作方式类似上面的 “反向” 一对多关联。</p>
<p>不同点在为属性命名上：定义了 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a> 的模型使用字段名作为属性名，而 “反向” 模型使用源模型名的小写形式，加上 <code class="docutils literal notranslate"><span class="pre">'_set'</span></code> （就像反向一对多关联一样）。</p>
<p>一个更易理解的例子:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
<span class="n">e</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># Returns all Author objects for this Entry.</span>
<span class="n">e</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
<span class="n">e</span><span class="o">.</span><span class="n">authors</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">name__contains</span><span class="o">=</span><span class="s1">&#39;John&#39;</span><span class="p">)</span>

<span class="n">a</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">a</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># Returns all Entry objects for this Author.</span>
</pre></div>
</div>
<p>和 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 一样， <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a> 能指定 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField.related_name" title="django.db.models.ManyToManyField.related_name"><code class="xref py py-attr docutils literal notranslate"><span class="pre">related_name</span></code></a>。在上面的例子中，若 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 中的 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ManyToManyField" title="django.db.models.ManyToManyField"><code class="xref py py-class docutils literal notranslate"><span class="pre">ManyToManyField</span></code></a> 已指定了 <code class="docutils literal notranslate"><span class="pre">related_name='entries'</span></code>，随后每个 <code class="docutils literal notranslate"><span class="pre">Author</span></code> 实例会拥有一个 <code class="docutils literal notranslate"><span class="pre">entries</span></code> 属性，而不是 <code class="docutils literal notranslate"><span class="pre">entry_set</span></code>。</p>
<p>另一个与一对多关联不同的地方是，除了模型实例以外，多对多关联中的 <code class="docutils literal notranslate"><span class="pre">add()</span></code>， <code class="docutils literal notranslate"><span class="pre">set()</span></code> 和 <code class="docutils literal notranslate"><span class="pre">remove()</span></code> 方法能接收主键值。例如，若 <code class="docutils literal notranslate"><span class="pre">e</span></code> 和 <code class="docutils literal notranslate"><span class="pre">e2</span></code> 是 <code class="docutils literal notranslate"><span class="pre">Entry</span></code> 的实例，以下两种 <code class="docutils literal notranslate"><span class="pre">set()</span></code> 调用结果一致:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">Author</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">a</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">set</span><span class="p">([</span><span class="n">e1</span><span class="p">,</span> <span class="n">e2</span><span class="p">])</span>
<span class="n">a</span><span class="o">.</span><span class="n">entry_set</span><span class="o">.</span><span class="n">set</span><span class="p">([</span><span class="n">e1</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span> <span class="n">e2</span><span class="o">.</span><span class="n">pk</span><span class="p">])</span>
</pre></div>
</div>
</div>
<div class="section" id="s-one-to-one-relationships">
<span id="one-to-one-relationships"></span><h3>一对一关联<a class="headerlink" href="#one-to-one-relationships" title="永久链接至标题">¶</a></h3>
<p>一对一关联与多对一关联非常类似。若在模型中定义了 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.OneToOneField" title="django.db.models.OneToOneField"><code class="xref py py-class docutils literal notranslate"><span class="pre">OneToOneField</span></code></a>，该模型的实例只需通过其属性就能访问关联对象。</p>
<p>例如:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">EntryDetail</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">entry</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">OneToOneField</span><span class="p">(</span><span class="n">Entry</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">)</span>
    <span class="n">details</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>

<span class="n">ed</span> <span class="o">=</span> <span class="n">EntryDetail</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">ed</span><span class="o">.</span><span class="n">entry</span> <span class="c1"># Returns the related Entry object.</span>
</pre></div>
</div>
<p>不同点在于 “反向” 查询。一对一关联所关联的对象也能访问 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 对象，但这个 <a class="reference internal" href="managers.html#django.db.models.Manager" title="django.db.models.Manager"><code class="xref py py-class docutils literal notranslate"><span class="pre">Manager</span></code></a> 仅代表一个对象，而不是对象的集合:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">e</span><span class="o">.</span><span class="n">entrydetail</span> <span class="c1"># returns the related EntryDetail object</span>
</pre></div>
</div>
<p>若未为关联关系指定对象，Django 会抛出 <code class="docutils literal notranslate"><span class="pre">DoesNotExist</span></code> 异常。</p>
<p>实例能通过为正向关联指定关联对象一样的方式指定给反向关联:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">e</span><span class="o">.</span><span class="n">entrydetail</span> <span class="o">=</span> <span class="n">ed</span>
</pre></div>
</div>
</div>
<div class="section" id="s-how-are-the-backward-relationships-possible">
<span id="how-are-the-backward-relationships-possible"></span><h3>反向关联是如何实现的？<a class="headerlink" href="#how-are-the-backward-relationships-possible" title="永久链接至标题">¶</a></h3>
<p>其它对象关联映射实现要求你在两边都定义关联关系。而 Django 开发者坚信这违反了 DRY 原则（不要自我重复），故 Django 仅要求你在一端定义关联关系。</p>
<p>但这是如何实现的呢，给你一个模型类，模型类并不知道是否有其它模型类关联它，直到其它模型类被加载？</p>
<p>答案位于 <a class="reference internal" href="../../ref/applications.html#django.apps.apps" title="django.apps.apps"><code class="xref py py-data docutils literal notranslate"><span class="pre">应用注册</span></code></a>。 Django 启动时，它会导入 <a class="reference internal" href="../../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 列出的每个应用，和每个应用中的 <code class="docutils literal notranslate"><span class="pre">model</span></code> 模块。无论何时创建了一个新模型类，Django 为每个关联模型添加反向关联。若被关联的模型未被导入，Django 会持续追踪这些关联，并在关联模型被导入时添加关联关系。</p>
<p>出于这个原因，包含你所使用的所有模型的应用必须列在 <a class="reference internal" href="../../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 中。否则，反向关联可能不会正常工作。</p>
</div>
<div class="section" id="s-queries-over-related-objects">
<span id="queries-over-related-objects"></span><h3>查询关联对象<a class="headerlink" href="#queries-over-related-objects" title="永久链接至标题">¶</a></h3>
<p>涉及关联对象的查询与涉及普通字段的查询遵守同样的规则。未查询条件指定值时，你可以使用对象实例，或该实例的主键。</p>
<p>例如，若有个博客对象 <code class="docutils literal notranslate"><span class="pre">b</span></code>，其 <code class="docutils literal notranslate"><span class="pre">id=5</span></code>，以下三种查询是一样的:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog</span><span class="o">=</span><span class="n">b</span><span class="p">)</span> <span class="c1"># Query using object instance</span>
<span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog</span><span class="o">=</span><span class="n">b</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="c1"># Query using id from instance</span>
<span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># Query using id directly</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="s-falling-back-to-raw-sql">
<span id="falling-back-to-raw-sql"></span><h2>回归原生 SQL<a class="headerlink" href="#falling-back-to-raw-sql" title="永久链接至标题">¶</a></h2>
<p>若你发现需要编写的 SQL 查询语句太过复杂，以至于 Django 的数据库映射无法处理，你可以回归手动编写 SQL。Django 针对编写原生 SQL 有几个选项；参考 <a class="reference internal" href="sql.html"><span class="doc">执行原生 SQL 查询</span></a>。</p>
<p>最后，Django 数据库层只是一种访问数据库的接口，理解这点非常重要。你也可以通过其它工具，编程语言或数据库框架访问数据库；Django 并没有对数据库数据库做啥独有的操作。</p>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">执行查询</a><ul>
<li><a class="reference internal" href="#creating-objects">创建对象</a></li>
<li><a class="reference internal" href="#saving-changes-to-objects">将修改保存至对象</a><ul>
<li><a class="reference internal" href="#saving-foreignkey-and-manytomanyfield-fields">保存 <code class="docutils literal notranslate"><span class="pre">ForeignKey</span></code> 和 <code class="docutils literal notranslate"><span class="pre">ManyToManyField</span></code> 字段</a></li>
</ul>
</li>
<li><a class="reference internal" href="#retrieving-objects">检索对象</a><ul>
<li><a class="reference internal" href="#retrieving-all-objects">检索全部对象</a></li>
<li><a class="reference internal" href="#retrieving-specific-objects-with-filters">通过过滤器检索指定对象</a><ul>
<li><a class="reference internal" href="#chaining-filters">链式过滤器</a></li>
<li><a class="reference internal" href="#filtered-querysets-are-unique">每个 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 都是唯一的</a></li>
<li><a class="reference internal" href="#querysets-are-lazy"><code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 是惰性的</a></li>
</ul>
</li>
<li><a class="reference internal" href="#retrieving-a-single-object-with-get">用 <code class="docutils literal notranslate"><span class="pre">get()</span></code> 检索单个对象</a></li>
<li><a class="reference internal" href="#other-queryset-methods">其它 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 方法</a></li>
<li><a class="reference internal" href="#limiting-querysets">限制 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 条目数</a></li>
<li><a class="reference internal" href="#field-lookups">字段查询</a></li>
<li><a class="reference internal" href="#lookups-that-span-relationships">跨关系查询</a><ul>
<li><a class="reference internal" href="#spanning-multi-valued-relationships">跨多值关联</a></li>
</ul>
</li>
<li><a class="reference internal" href="#filters-can-reference-fields-on-the-model">过滤器可以为模型指定字段</a></li>
<li><a class="reference internal" href="#expressions-can-reference-transforms">Expressions can reference transforms</a></li>
<li><a class="reference internal" href="#the-pk-lookup-shortcut">主键 (<code class="docutils literal notranslate"><span class="pre">pk</span></code>) 查询快捷方式</a></li>
<li><a class="reference internal" href="#escaping-percent-signs-and-underscores-in-like-statements">在 <code class="docutils literal notranslate"><span class="pre">LIKE</span></code> 语句中转义百分号和下划线</a></li>
<li><a class="reference internal" href="#caching-and-querysets">缓存和 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code></a><ul>
<li><a class="reference internal" href="#when-querysets-are-not-cached">当 <code class="docutils literal notranslate"><span class="pre">QuerySet</span></code> 未被缓存时</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#querying-jsonfield">查询 <code class="docutils literal notranslate"><span class="pre">JSONField</span></code></a><ul>
<li><a class="reference internal" href="#storing-and-querying-for-none">保存和查询 <code class="docutils literal notranslate"><span class="pre">None</span></code> 值</a></li>
<li><a class="reference internal" href="#key-index-and-path-transforms">Key, index, 和路径转换</a></li>
<li><a class="reference internal" href="#containment-and-key-lookups">包含与键查找</a><ul>
<li><a class="reference internal" href="#contains"><code class="docutils literal notranslate"><span class="pre">contains</span></code></a></li>
<li><a class="reference internal" href="#contained-by"><code class="docutils literal notranslate"><span class="pre">contained_by</span></code></a></li>
<li><a class="reference internal" href="#has-key"><code class="docutils literal notranslate"><span class="pre">has_key</span></code></a></li>
<li><a class="reference internal" href="#has-keys"><code class="docutils literal notranslate"><span class="pre">has_keys</span></code></a></li>
<li><a class="reference internal" href="#has-any-keys"><code class="docutils literal notranslate"><span class="pre">has_any_keys</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#complex-lookups-with-q-objects">通过 <code class="docutils literal notranslate"><span class="pre">Q</span></code> 对象完成复杂查询</a></li>
<li><a class="reference internal" href="#comparing-objects">比较对象</a></li>
<li><a class="reference internal" href="#deleting-objects">删除对象</a></li>
<li><a class="reference internal" href="#copying-model-instances">复制模型实例</a></li>
<li><a class="reference internal" href="#updating-multiple-objects-at-once">一次修改多个对象</a></li>
<li><a class="reference internal" href="#related-objects">关联对象</a><ul>
<li><a class="reference internal" href="#one-to-many-relationships">一对多关联</a><ul>
<li><a class="reference internal" href="#forward">正向访问</a></li>
<li><a class="reference internal" href="#following-relationships-backward">“反向” 关联</a></li>
<li><a class="reference internal" href="#using-a-custom-reverse-manager">使用自定义反向管理器</a></li>
<li><a class="reference internal" href="#additional-methods-to-handle-related-objects">管理关联对象的额外方法</a></li>
</ul>
</li>
<li><a class="reference internal" href="#many-to-many-relationships">多对多关联</a></li>
<li><a class="reference internal" href="#one-to-one-relationships">一对一关联</a></li>
<li><a class="reference internal" href="#how-are-the-backward-relationships-possible">反向关联是如何实现的？</a></li>
<li><a class="reference internal" href="#queries-over-related-objects">查询关联对象</a></li>
</ul>
</li>
<li><a class="reference internal" href="#falling-back-to-raw-sql">回归原生 SQL</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="models.html"
                        title="上一章">模型</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="aggregation.html"
                        title="下一章">聚合</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../../_sources/topics/db/queries.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="models.html" title="模型">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="aggregation.html" title="聚合">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>